package com.waymap.utils;


import com.waymap.common.Constant;
import com.xiaoleilu.hutool.lang.Base64;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SignatureException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * Created by tim on 2018/7/19.
 */
public class AuthonTokenUtil {
    private static final Logger logger = LoggerFactory.getLogger(AuthonTokenUtil.class);
    //创建token,生成随机唯一字符串
    public static Map createToken(Map subMap){
        Map map = new HashMap();
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setId(subMap.get("id")+"")
                .setSubject(subMap.get("subject")+"")
                .setIssuer(subMap.get("isssuer")+"")
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, secretKey);
        long ttlMillis =Constant.TOKEN_TTL;//设置token有效时间
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            map.put("limitedTime",expMillis);
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 过期时间
        }
        map.put("token",builder.compact());
        return map;
    }

    public static Claims parseToken(String token) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
    }

    //检测token
    public static Map checkToken(String token,String userId){
        Map map = new HashMap();
        map.put("isAvailable",Constant.YES);
        map.put("errorCode","");
        map.put("msg","");
        //检测token是否合法
        if (StringUtils.isEmpty(token)) {
            map.put("isAvailable",Constant.NO);
            map.put("errorCode",Constant.TOKEN_ERRCODE_NULL);
            map.put("msg","签名验证不存在");
            return map;
        }
        //验证JWT的签名，返回CheckResult对象
        Constant checkResult = validateJWT(token);
        if (!checkResult.isSuccess()) {
            String msg = "签名验证不通过";
            switch (checkResult.getErrCode()) {
                // 签名验证不通过
                case Constant.TOKEN_ERRCODE_FAIL:
                    msg = "签名验证不通过";
                    break;
                // 签名过期，返回过期提示码
                case Constant.TOKEN_ERRCODE_EXPIRE:
                    msg = "签名过期";
                    break;
                default:
                    break;
            }
            map.put("isAvailable",Constant.NO);
            map.put("errorCode",checkResult.getErrCode());
            map.put("msg",msg);
            return map;
        }
        String tokenId = checkResult.getClaims().getId();
        logger.info("tokenId="+tokenId);
        if(!tokenId.equals(userId)){
            map.put("isAvailable",Constant.NO);
            map.put("errorCode",Constant.TOKEN_ERRCODE_NULL);
            map.put("msg","签名信息不合法");
        }
        return map;
    }

    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(Constant.TOKEN_SECERT);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    public static Constant validateJWT(String jwtStr) {
        Constant checkResult = new Constant();
        Claims claims = null;
        try {
            claims = parseToken(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(Constant.TOKEN_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(Constant.TOKEN_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(Constant.TOKEN_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

}
